using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using W3C.Soap;

using webcam = Microsoft.Robotics.Services.WebCam.Proxy;
using Microsoft.Ccr.Adapters.WinForms;

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

using submgr = Microsoft.Dss.Services.SubscriptionManager;
using System.IO;
using System.Xml;

using System.Xml.Serialization;




namespace UrbanCam
{
	[Contract(Contract.Identifier)]
	[DisplayName("Urban Cam")]
	[Description("Urban Cam service (no description provided)")]
	class UrbanCamService : DsspServiceBase
	{
        webcam.WebCamOperations webcamPort = null;
        //webcam.WebCamOperations webcamPort2 = null;

        webcam.WebCamOperations webcamSubscribePort = null;

        SignalData _SignalDat = new SignalData();
 
        Vison _Vision = new Vison(128, 128);

		[ServiceState]
		UrbanCamState _state = new UrbanCamState();
		
		[ServicePort("/UrbanCam", AllowMultipleInstances = true)]
		UrbanCamOperations _mainPort = new UrbanCamOperations();


        [Partner("SubMgr", Contract = submgr.Contract.Identifier, CreationPolicy = PartnerCreationPolicy.CreateAlways)]
        private submgr.SubscriptionManagerPort _subMgrPort = new submgr.SubscriptionManagerPort();


		public UrbanCamService(DsspServiceCreationPort creationPort)
			: base(creationPort)
		{
		}
		
		protected override void Start()
		{
            Activate(Arbiter.Interleave(
                new TeardownReceiverGroup
                (
                    Arbiter.Receive<DsspDefaultDrop>(false, _mainPort, DropHandler)
                ),
                new ExclusiveReceiverGroup
                (
                    Arbiter.ReceiveWithIterator<Connect>(true, _mainPort, ConnectHandler)
                    
                ),
                new ConcurrentReceiverGroup
                (
                Arbiter.Receive<DsspDefaultLookup>(true, _mainPort, DefaultLookupHandler),
                Arbiter.ReceiveWithIterator<NotifySignal>(true, _mainPort, NotifySignalHandler),
                    Arbiter.Receive<DsspDefaultLookup>(true, _mainPort, DefaultLookupHandler),
                    Arbiter.ReceiveWithIterator<Subscribe>(true, _mainPort, SubscribeHandler),
                    Arbiter.ReceiveWithIterator<SetUpdate>(true, _mainPort, SetUpdateHandler)

                    
                )
            ));

            DirectoryInsert();

            WinFormsServicePort.Post(new RunForm(CreateAppForm));

            XmlSerializer s = new XmlSerializer(_SignalDat.GetType());
            using (TextReader r = new StreamReader(@"robochamps/urban/AI/signal.xml"))
            {
                SignalData SignalDat = (SignalData)s.Deserialize(r);
                if (SignalDat != null)
                {
                    LogInfo("signal.xml load Success");
                    _SignalDat = SignalDat;
                }
                else
                {
                    LogInfo("signal.xml load fail");
                }

            }


            //XmlSerializer s = new XmlSerializer(_SignalDat.GetType());
            //TextWriter w = new StreamWriter(@"robochamps/urban/AI/signal.xml");
            //s.Serialize(w, _SignalDat);
            //w.Close();



		}

        CamImageForm _form;

        CamImageForm CreateAppForm()
        {
            _form = new CamImageForm(_mainPort);
            return _form;
        }

        void DropHandler(DsspDefaultDrop drop)
        {
            if (_form != null)
            {
                CamImageForm form = _form;
                _form = null;

                WinFormsServicePort.FormInvoke(
                    delegate()
                    {
                        if (!form.IsDisposed)
                        {
                            form.Dispose();
                        }
                    }
                );
            }

            base.DefaultDropHandler(drop);
        }

        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        public virtual IEnumerator<ITask> ConnectHandler(Connect update)
        {
            string camUrl = "";

            if (update.Body.CamUriName == null)
                camUrl = "Camera1"; 
            else
                camUrl = update.Body.CamUriName;

            webcamPort = ServiceForwarder<webcam.WebCamOperations>("/" + "Camera2");
            //webcamPort2 = ServiceForwarder<webcam.WebCamOperations>("/" + "Camera2");


            webcamSubscribePort = new webcam.WebCamOperations();
            //webcamSubscribePort2 = new webcam.WebCamOperations();

            

            yield return Arbiter.Choice<SubscribeResponseType, W3C.Soap.Fault>(
                webcamPort.Subscribe(webcamSubscribePort),
                delegate(SubscribeResponseType response)
                {
                    Activate(Arbiter.ReceiveWithIterator<webcam.UpdateFrame>(false, webcamSubscribePort, updateFrameHandler));

                    WinFormsServicePort.Post(new FormInvoke(delegate()
                    {
                        try
                        {
                            _form.label1.Text = camUrl;
                        }
                        catch (Exception ex)
                        {
                            LogInfo(ex.ToString());
                            Console.WriteLine(ex);
                        }
                    }));
                },
                delegate(W3C.Soap.Fault fault)
                {
                    Console.WriteLine("CAM Failed to Subscribe " + fault.ToException());
                });


            //yield return Arbiter.Choice<SubscribeResponseType, W3C.Soap.Fault>(
            //    webcamPort2.Subscribe(webcamSubscribePort),
            //    delegate(SubscribeResponseType response)
            //    {
            //        Activate(Arbiter.ReceiveWithIterator<webcam.UpdateFrame>(false, webcamSubscribePort, updateFrameHandler2));

            //        WinFormsServicePort.Post(new FormInvoke(delegate()
            //        {
            //            try
            //            {
            //                _form.label2.Text = camUrl;
            //            }
            //            catch (Exception ex)
            //            {
            //                LogInfo(ex.ToString());
            //                Console.WriteLine(ex);
            //            }
            //        }));
            //    },
            //    delegate(W3C.Soap.Fault fault)
            //    {
            //        Console.WriteLine("CAM Failed to Subscribe " + fault.ToException());
            //    });

            update.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            yield break;
        }



        //public IEnumerator<ITask> updateFrameHandler2(webcam.UpdateFrame up)
        //{
        //    webcam.QueryFrameRequest req = new Microsoft.Robotics.Services.WebCam.Proxy.QueryFrameRequest();
        //    req.Format = System.Drawing.Imaging.ImageFormat.Bmp.Guid;
        //    req.Size = new Microsoft.Robotics.PhysicalModel.Proxy.Vector2(128, 128);
        //    yield return Arbiter.Choice<webcam.QueryFrameResponse, W3C.Soap.Fault>(
        //        webcamPort2.QueryFrame(req),
        //        delegate(webcam.QueryFrameResponse response)
        //        {
        //            WinFormsServicePort.Post(new FormInvoke(delegate()
        //            {
        //                try
        //                {
        //                    ///System.IO.MemoryStream mem = new System.IO.MemoryStream(response.Frame);
        //                    //_form.pictureBox2.Image = new System.Drawing.Bitmap(mem);
        //                }
        //                catch (Exception ex)
        //                {
        //                    LogInfo(ex.ToString());
        //                    Console.WriteLine(ex);
        //                }
        //            }));
        //        },
        //        delegate(W3C.Soap.Fault fault)
        //        {
        //        });
        //    Activate(Arbiter.ReceiveWithIterator<webcam.UpdateFrame>(false, webcamSubscribePort, updateFrameHandler2));
        //    yield break;
        //}

        

        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public IEnumerator<ITask> SetUpdateHandler(SetUpdate setUpdate)
        {
            _bOnUpte = setUpdate.Body.bUpdate;
            yield break;
        }


        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public IEnumerator<ITask> SubscribeHandler(Subscribe subscribe)
        {
            SubscribeHelper(_subMgrPort, subscribe.Body, subscribe.ResponsePort);
            yield break;
        }

        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public virtual IEnumerator<ITask> NotifySignalHandler(NotifySignal update)
        {

            SendNotification<NotifySignal>(_subMgrPort, update.Body);

            yield break;
        }

        bool _bOnUpte = true;

        public IEnumerator<ITask> updateFrameHandler(webcam.UpdateFrame up)
        {
            webcam.QueryFrameRequest req = new Microsoft.Robotics.Services.WebCam.Proxy.QueryFrameRequest();
            req.Format = System.Drawing.Imaging.ImageFormat.Bmp.Guid;
            req.Size = new Microsoft.Robotics.PhysicalModel.Proxy.Vector2(128, 128);


            NotifySignalState body = new NotifySignalState();

            //if (_bOnUpte == true)
            {

                yield return Arbiter.Choice<webcam.QueryFrameResponse, W3C.Soap.Fault>(
                    webcamPort.QueryFrame(req),
                    delegate(webcam.QueryFrameResponse response)
                    {
                        WinFormsServicePort.Post(new FormInvoke(delegate()
                        {
                            try
                            {
                                ColorVector r = new ColorVector(_SignalDat._Red_R, _SignalDat._Red_G, _SignalDat._Red_B, _SignalDat._Red_similarity);
                                ColorVector g = new ColorVector(_SignalDat._Green_R, _SignalDat._Green_G, _SignalDat._Green_B, _SignalDat._Green_similarity);
                                ColorVector b = new ColorVector(30, 30, 30, 0.995d);
                                //byte [] frame = response.Frame + 54;

                                //frame = response;

                                //webcam.QueryFrameResponse frame = response;

                                System.IO.MemoryStream mem = new System.IO.MemoryStream(response.Frame);
                                System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(mem);

                                //System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(response.Size.Width, response.Size.Height, PixelFormat.Format32bppArgb);
                                BitmapData data = bmp.LockBits(new Rectangle(0, 0, response.Size.Width, response.Size.Height),
                                        ImageLockMode.ReadOnly,
                                        PixelFormat.Format32bppArgb);

                                Bitmap Bmp8 = new Bitmap(response.Size.Width, response.Size.Height, PixelFormat.Format8bppIndexed);
                                BitmapData data8 = Bmp8.LockBits(new Rectangle(0, 0, response.Size.Width, response.Size.Height),
                                        ImageLockMode.ReadWrite,
                                        PixelFormat.Format8bppIndexed);

                                _Vision.ProcessFrameHandler(r, g, b, 0, data, data8, body);

                                if (_bOnUpte == false)
                                {
                                    body.RCount = uint.MaxValue;
                                    body.GCount = uint.MaxValue;

                                }

                                //Marshal.Copy(frame, 0, data.Scan0, response.Size.Width * response.Size.Height * 4);
                                bmp.UnlockBits(data);
                                Bmp8.UnlockBits(data8);
                                _form.pictureBox1.Image = Bmp8;

                                _mainPort.Post(new NotifySignal(body));


                            }
                            catch (Exception ex)
                            {
                                LogInfo(ex.ToString());
                                Console.WriteLine(ex);
                            }
                        }));
                    },
                    delegate(W3C.Soap.Fault fault)
                    {
                    });
            
            }

            

            Activate(Arbiter.ReceiveWithIterator<webcam.UpdateFrame>(false, webcamSubscribePort, updateFrameHandler));
            yield break;
        }
	}
}



